package com.learn.spring.test;

import com.learn.spring.WebfluxService;
import com.learn.spring.reactor8.ObserverDemo;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Case10 {
    /**
     * Spring5 框架新功能
     * 1. Spring Webflux 介绍
     *  (1) 是 Spring5 添加新的模块，用于 web 开发的，功能 SpringMVC 类似的，Webflux 使用当前一种比较流程响应式编程出现的框架。
     *  (2) 使用传统 web 框架，比如 SpringMVC 这些基于 Servlet 容器，Webflux 是一种异步非阻塞的框架，异步非阻塞的框架在 Servlet3.1 以后才支持的，
     *      而 Spring 的核心是基于 Reactor 的相关 API 实现
     *  (3) 异步和同步、阻塞和非阻塞
     *      异步和同步针对调用者，调用者发送请求，如果等着对方回应之后才去做其他事情就是同步，如果发送请求之后不等着对方回应就去做其他事情就是异步
     *      阻塞和非阻塞针对被调用者，被调用者受到请求之后，做完请求任务之后才给出反馈就是阻塞，受到请求之后马上给出反馈然后再去做事情就是非阻塞
     *  (4) Webflux特点:
     *      第一非阻塞式: 在有限资源下，提高系统吞吐量和伸缩性，以 Reactor 为基础实现响应式编程
     *      第二函数式编程: Spring5 框架基于 java8，Webflux 使用 Java8 函数式编程方式实现路由请求
     *  (5) Spring MVC 与 Webflux 比较
     *      第一 两个框架都可以使用注解方式，都运行在 Tomcat 等容器中
     *      第二 SpringMVC 采用命令式编程，Webflux 采用异步响应式编程
     *
     * 2.响应式编程
     *      响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流，而相关的计算模型会自动将变化的值通过数据流进行传播。
     *
     * 3. Webflux 执行流程 和 核心API
     *  (1) 基于 Netty 的 nio库
     *  (2) SpringWebflux 执行过程和 SpringMVC 相似的
     *      SpringWebflux 核心控制器 DispatchHandler 实现接口 WebHandler
     *      接口WebHandler有一个方法
     *      {@link org.springframework.web.server.WebHandler#handle }
     *      {@link org.springframework.web.reactive.DispatcherHandler#handle }
     *  (3) SpringWebflux 里面 DispatcherHandler，负责请求的处理
     *      HandlerMapping:请求查询到处理的方法
     *      HandlerAdapter:真正负责请求处理
     *      HandlerResultHandler:响应结果处理
     *  (4) SpringWebflux实现函数式编程，两个接口: RouterFunction 和 HandlerFunction
     *      RouterFunction 实现路由功能将请求转发给对应的 handler处理
     *      HandlerFunction 用来响应你的请求的具体过程
     *
     *
     * 4. Spring Webflux 基于注解的编程模型
     *    {@link com.learn.spring.controller.FluxController}
     *
     * 5. Spring Webflux 基于函数式编程模型
     *  (1) 在使用函数式编程模型操作时候，需要自己初始化服务器v
     *  (2) 基于函数式编程模型时候，有两个核心接口:RouterFunction(实现路由功能，请求转发给对应的 handler〉和 HandlerFunction(处理请求生成响应的函数〉。核心任务定义两个函数式接口的实现并且启动需要的服务器。
     *  (3) SpringWebflux 请求和响应不再是 ServletRequest 和 ServletResponse，而是 ServerRequest 和 ServerResponse
     *  (4) 具体实现
     *      1) 创建 handler
     *          {@link com.learn.spring.handler.FluxHandler}
     *      2) 初始化服务器，编写 Router
     *          {@link WebfluxService#routingFunction()}
     *      3) 创建服务完成适配
     *          {@link WebfluxService#createReactorServer()}
     *      4) 最终调用
     *          {@link WebfluxService#main(String[])}
     *  (5) 使用 WebClinet 调用
     *
     */

    /**
     * JAVA 实现响应式编程
     */
    @Test
    public void test1() {
        // JAVA8 中的响应式编程采用 观察者模式完成， JAVA9 中的采用 Flow 类，里面包含了订阅（Publisher），与RXJAVA十分相似。
        ObserverDemo observer = new ObserverDemo();
        observer.addObserver((o, agr) -> {
            System.out.println("改变了==>" + agr);
        });
        observer.addObserver((o, agr) -> {
            System.out.println("改变了");
        });
        observer.addNumber();
    }

    /**
     * Reactor 框架接口实现响应式编程
     * (1) 响应式编程操作中，Reactor 是满足 Reactive 规范框架
     * (2) Reactor 有两个核心类，Mono 和 Flux，这两个类实现接口 Publisher.提供了丰富的操作符。
     *      Flux对象实现发布者，返回N个元素;Mono实现翻发布者，返回0或者1个元素.
     * (3) Flux 和 Mono 都是数据流的发布者，使用 Flux 和 Mono 都可以发出三种数据信号:
     *      元素值，
     *      错误信号，
     *      完成信号，
     *  错误信号和完成信号都代表终止信号，终止信号用于告诉订阅者数据流结束了,
     *  Flux : ----O----O----O---|--->
     *  Mono : ---O----|---->
     *  O代表连续发送的数据值 | 代表的事终止信号， -----> 时间轴 数据流向
     *
     *  (4) 实现代码需要添加依赖
     *      io.projectreactor.reactor-core
     *  (5) 三种信号特点
     *      错误信号和完成信号都是终止信号，不能共存的
     *      如果没有发送任何元素值，而是直接发送错误或者完成信号，表示是空数据流.
     *      如果没有错误信号，没有完成信号，表示是无限数据流
     *  (6) 调用just或者其他方法只是声明数据流，数据流并没有发出，只有进行订阅之后才会触发数据流，不订阅什么都不会发生的
     *
     *  (7) 操作符
     *      对数据流进行一道道操作,成为操作符,比如工厂流水线. 订阅相当于吧一个数据流行为单独的拿出来成为了一个程序，程序是对数据的加工，原本的行代码用来处理数据，变成了现在流程中的一个操作符。
     *      常用操作符：
     *      1. map  把每个元素映射为新的元素
     *      2. flatMap 把每个元素映射为一个流，然后把每个流合并成一个大流
     *
     */
    @Test
    public void test2() {
        Flux.just(1, 2, 3).subscribe(System.out::println);
        Mono.just(1).subscribe(System.out::println);

//        // 其他方法
//        Integer[] array = {1,2,3,4};
//        Flux.fromArray(array);
//        List<Integer> list = Arrays.asList(array);
//        Flux.fromIterable(list);
//        Stream<Integer> stream = list.stream();
//        Flux.fromStream(stream);
    }

}
